#ifndef __WD_FUNC_H
#define __WD_FUNC_H

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <errno.h>
#include <error.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <signal.h>
#include <dirent.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/epoll.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <pthread.h>
#include <sys/uio.h>
#include <sys/sendfile.h>
#include <shadow.h>
#include <crypt.h>
#include <syslog.h>
#include <mysql/mysql.h>


#define SIZE(a) (sizeof(a)/sizeof(a[0]))

typedef void (*sighandler_t)(int);

#define ARGS_CHECK(argc, num)   {\
    if(argc != num){\
        fprintf(stderr, "ARGS ERROR!\n");\
        return -1;\
    }}

#define ERROR_CHECK(ret, num, msg) {\
    if(ret == num) {\
        perror(msg);\
        return -1;\
    }}

#define THREAD_ERROR_CHECK(ret, func) {\
    if(ret != 0) {\
        fprintf(stderr, "%s:%s\n", func, strerror(ret));\
    }}

//检查mysql在prepare过程中的某些错误
#define ERROR_CHECK_STMT(stmt, conn){\
    fprintf(stderr, "(%d,%s)\n", \
            mysql_stmt_errno(stmt), \
            mysql_stmt_error(stmt));\
    mysql_close(conn);\
    return EXIT_FAILURE;\
}

//命令类型
typedef enum {
    CMD_TYPE_PWD=1,
    CMD_TYPE_LS,
    CMD_TYPE_CD,
    CMD_TYPE_MKDIR,
    CMD_TYPE_RMDIR,
    CMD_TYPE_RMFILE,
    CMD_TYPE_LOGIN1,
    CMD_TYPE_LOGIN2,
    CMD_TYPE_PUTS,
    CMD_TYPE_GETS,
    CMD_TYPE_REG1,
    CMD_TYPE_REG2,
    CMD_TYPE_NOTCMD  //不是命令
} CmdType;


//消息类型
typedef enum {
    MSG_TYPE_SUCCESS = 1,
    MSG_TYPE_DUPLICATE,
    MSG_TYPE_FAILURE,
    MSG_TYPE_NOT_EXIST,
    MSG_TYPE_WRONG_PASSWORD,
    MSG_TYPE_ERROR_MYSQL,
    MSG_TYPE_TRANSFER_SECOND,
    MSG_TYPE_TRANSFER_NORMAL
} MsgType;
//消息结构体，用于回复
typedef struct{
    int len;    //data中数据的长度
    MsgType type;
    char data[1000];
} Msg;


//用户结点
typedef struct Node{
    int fd;
    int userid;
    struct Node *next;
} UserNode;

//用户链表
typedef struct{
    UserNode* front;
    UserNode* rear;
} User;

//目录栈结点
typedef struct DirNode{
    char dirname[128];
    struct DirNode* next;
} DirNode;
//目录栈
typedef struct{
    int node_num;
    DirNode* front;
} DirStack;

typedef struct 
{
    int len;//记录内容长度
    char buff[1000];//记录内容本身
}train_t;

typedef struct task_s{
    int peerfd;
    CmdType type;
    char data[1000];
    struct task_s * pNext;
}task_t;

typedef struct task_queue_s
{
    task_t * pFront;
    task_t * pRear;
    int queSize;//记录当前任务的数量
    pthread_mutex_t mutex; 
    pthread_cond_t cond;
    int flag;//0 表示要退出，1 表示不退出

}task_queue_t;

typedef struct threadpool_s {
    pthread_t * pthreads;
    int pthreadNum;
    task_queue_t que;//...任务队列
}threadpool_t;

//对用户链表的操作
int delUser(int fd, int userid);
int addUser(int fd, int userid);
int getUserid(int fd, int * userid);
int destroyUsers();

//对目录栈的操作
void initDirStack(DirStack* s);
void pushDirStack(DirStack* s, const char* filename);
void getDirPath(DirStack* s, char* path);
void destroyDirStack(DirStack* s);

int queueInit(task_queue_t * que);
int queueDestroy(task_queue_t * que);
int queueIsEmpty(task_queue_t * que);
int taskSize(task_queue_t * que);
int taskEnque(task_queue_t * que, task_t * task);
task_t * taskDeque(task_queue_t * que);
int broadcastALL(task_queue_t* que);

int threadpoolInit(threadpool_t *, int num);
int threadpoolDestroy(threadpool_t *);
int threadpoolStart(threadpool_t *);
int threadpoolStop(threadpool_t *);


int tcpInit(const char * ip, const char * port);
int addEpollReadfd(int epfd, int fd);
int delEpollReadfd(int epfd, int fd);
int transferFile(int sockfd);
int sendn(int sockfd, const void * buff, int len);
int recvn(int sockfd, void * buff, int len);
//发送消息给客户端
int sendMsg(int sockfd, MsgType type, char* data);

//处理客户端发过来的消息
void handleMessage(int sockfd, task_queue_t * que);

//执行任务的总的函数
void doTask(task_t * task);
//每一个具体命令的执行
void cdCommand(task_t * task);
void lsCommand(task_t * task);
void pwdCommand(task_t * task);
void mkdirCommand(task_t * task);
void rmdirCommand(task_t * task);
void rmfileCommand(task_t* task);
void loginCommand1(task_t * task);
void loginCommand2(task_t * task);
void regCommand1(task_t * task);
void regCommand2(task_t * task);
void notCommand(task_t * task);
void getsCommand(task_t* task);
void putsCommand(task_t* task);


//在和sql服务器交互过程中封装的一些方法
//生成盐值(12个字符)
void getsalt(char* salt_buf);
//为MYSQL_BIND绑定输入参数
void bind_input(MYSQL_BIND * bind,
                enum enum_field_types bufftype, 
                void* buffer,
                unsigned long* len, _Bool* is_null);
//为MYSQL_BIND绑定输出参数
void bind_output(MYSQL_BIND * bind,
                 enum enum_field_types bufftype, 
                 void* buffer,
                 unsigned long len);

#endif
